#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>
#include<sys/types.h>

#define NUM 1024
#define SIZE 32
#define SEP " "

//用来保存完成的命令行字符串
char cmd_line[NUM];
//用来保存打散之后的命令行字符串
char *g_argv[SIZE];

//shell 运行原理：通过让子进程执行命令，让父进程等待&&解析命令
int main()
{
    //0.命令行解释器，一定是一个常驻内存的进程，不退出
    while(1)
    {
        //1.打印出提示信息
        //[np@localhost myshell]#
        printf("[root@localhost myshell]# ");
        fflush(stdout);
        memset(cmd_line, '\0', sizeof cmd_line);
        //2.过去用户的键盘输入[输入的是各种指令和选项："ls -a -l -i"]
        if (fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
        {
            continue;
        }
        cmd_line[strlen(cmd_line) - 1] = '\0';
        //ls -a -l -i\n
        //printf("echo: %s\n",cmd_line);
        //3.命令字符串解析："ls -a -l -i" -> "ls" "-a" "-l"
        g_argv[0] = strtok(cmd_line, SEP);//第一次调用，要传入原始字符串
        int index = 1;
        if (strcmp(g_argv[0], "ls") == 0)
        {
            g_argv[index++] = "--color=auto";            
        }
        if (strcmp(g_argv[0], "ll") == 0)
        {
            g_argv[0] = "ls";
            g_argv[index++] = "-l";
            g_argv[index++] = "--color=auto";
        }
        while (g_argv[index++] = strtok(NULL, SEP));////第二次，如果还要解析原始字符串，传入NULL
        
       // index = 0;
       // while (g_argv[index])
       // {
       //     printf("g_argv[%d]: %s\n", index, g_argv[index]);
       //     index++;
       // }
       // 4.TODO, 内置命令,让父进程(shell)自己执行的命令，叫做内置命令，内建命令
       // 内置命令本质其实就是shell中的一个函数调用
       if (strcmp(g_argv[0], "cd") == 0) //not child execute, father execute
       {
            if(g_argv[1] != NULL)
            {
                chdir(g_argv[1]);//cd path, cd ..

                continue;
            }
       }
       // 5.fork()
       pid_t id = fork();
        if (id == 0) //子进程
        {
            printf("下面功能让子进程执行\n");
            //cd cmd , current child path
            execvp(g_argv[0], g_argv);//ls -a -l -i
            exit(1);
        }
        //父进程
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if (ret > 0)
        {
            printf("exit code: %d\n", WEXITSTATUS(status));
        }
    }  
    
}
